﻿using BaiduBce.Services.Bos.Model;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using LimaLims.Application.Service.Equipment.Dto;
using LimaLims.Application.Service.Sys;
using LimaLims.Application.Service.Sys.Dto;
using LimaLims.Core;
using LimaLims.Core.Const;
using LimaLims.Core.Entity.Basic;
using LimaLims.Core.Entity.Equipment;
using LimaLims.Core.Entity.System;
using LimaLims.Core.Entity.TestCenter;
using LimaLims.Core.Enum;
using LimaLims.Core.Util;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MiniSoftware;
using System.Linq;
using System.Linq.Expressions;
using Yitter.IdGenerator;

namespace LimaLims.Application.Service.Equipment
{
    /// <summary>
    ///设备故障报修服务API
    /// </summary>
    [ApiDescriptionSettings(Name = "EquipmentRepair", Order = 161)]
    [Route("api")]
    public class EquipmentRepairService : IEquipmentRepairService, IDynamicApiController, ITransient
    {
        private readonly IRepository<EquipmentRepair> _equipmentRepairRep;
        private readonly IRepository<EquipmentInfo> _equipmentInfoRep;
        private readonly IGenerateCodeUtilService _generateCodeUtilService;//编码规则
        private readonly ISysMessageService _sysMessageService;
        private readonly IRepository<SysUser> _sysUserRep;
        public EquipmentRepairService(IRepository<EquipmentRepair> equipmentRepairRep, IGenerateCodeUtilService generateCode, IRepository<EquipmentInfo> equipmentInfoRep, IRepository<SysUser> sysUserRep, ISysMessageService sysMessageService)
        {
            _equipmentRepairRep = equipmentRepairRep;
            _generateCodeUtilService = generateCode;
            _equipmentInfoRep = equipmentInfoRep;
            _sysUserRep = sysUserRep;
            _sysMessageService = sysMessageService;
        }

        /// <summary>
        /// 发起单据
        /// </summary>
        [HttpPost("equipmentRepair/add")]
        [UnitOfWork]
        public async Task Add(AddEquipmentRepairInput input)
        {
            var isExist = await _equipmentRepairRep.DetachedEntities.AnyAsync(u => u.EquipmentId == input.EquipmentId && u.Status < DealStatus.Accepted);
            if (isExist)
                throw Oops.Oh("此设备已存在未处理报修单据！");
            if (string.IsNullOrWhiteSpace(input.Code))
            {
                input.Code = await _generateCodeUtilService.GenerateCode(BusinessType.EquipmentRepair);
            }
            EquipmentRepair equipmentRepair = input.Adapt<EquipmentRepair>();

            equipmentRepair.Id = YitIdHelper.NextId();
            // 保存并提交时：1.报修单据中备份原设备的设备状态 2.修改原设备的设备状态为报修中。
            if (input.Status == DealStatus.ToBeDeal)
            {
                // 报修单据中备份原设备的设备状态
                EquipmentInfo equipmentInfo = await _equipmentInfoRep.DetachedEntities.FirstOrDefaultAsync(s => s.Id == input.EquipmentId);
                equipmentRepair.EquipmentStatusBackup = equipmentInfo.EquipmentStatus;

                // 修改原设备的设备状态为报修中。
                equipmentInfo.EquipmentStatus = EquipmentStatus.reporting;
                await _equipmentInfoRep.UpdateIncludeAsync(entity: equipmentInfo, new[] { nameof(EquipmentInfo.EquipmentStatus) });
                //发送站内信-审核
                AddSysMessageInput message = new AddSysMessageInput
                {
                    Title = $"审核编号为{input.Code}仪器报修单据",
                    ParamId = equipmentRepair.Id,
                    Tag = "仪器报修",
                    Content = $"编号为{input.Code}的仪器报修单据需要审批处理。",
                    Url = "/equipment/equipmentRepair/handle",
                    Permission= "equipmentRepair:handle"
                };
                await _sysMessageService.AddSysMessage(message);
            }

            await equipmentRepair.InsertNowAsync();
        }

        /// <summary>
        /// 修改单据
        /// </summary>
        [HttpPost("equipmentRepair/edit")]
        [UnitOfWork]
        public async Task Edit(EditEquipmentRepairInput input)
        {
            var equipmentRepair = await _equipmentRepairRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (equipmentRepair == null)
                throw Oops.Oh("不存在此数据！");

            var isExist = await _equipmentRepairRep.DetachedEntities.AnyAsync(u => u.EquipmentId == input.EquipmentId && u.Status == DealStatus.ToBeSubmitted && u.Id != input.Id);
            if (isExist)
                throw Oops.Oh("此设备已存在报修单据！");

            var equipmentRepairModel = input.Adapt<EquipmentRepair>();

            // 保存并提交时：1.报修单据中备份原设备的设备状态 2.修改原设备的设备状态为报修中。
            if (input.Status == DealStatus.ToBeDeal)
            {
                // 报修单据中备份原设备的设备状态
                EquipmentInfo equipmentInfo = await _equipmentInfoRep.DetachedEntities.FirstOrDefaultAsync(s => s.Id == input.EquipmentId);
                equipmentRepairModel.EquipmentStatusBackup = equipmentInfo.EquipmentStatus;

                // 修改原设备的设备状态为报修中。
                equipmentInfo.EquipmentStatus = EquipmentStatus.reporting;
                await _equipmentInfoRep.UpdateIncludeAsync(entity: equipmentInfo, new[] { nameof(EquipmentInfo.EquipmentStatus) });

                //发送站内信-审核
                AddSysMessageInput message = new AddSysMessageInput
                {
                    Title = $"审核编号为{equipmentRepairModel.Code}仪器报修单据",
                    ParamId = equipmentRepair.Id,
                    Tag = "仪器报修",
                    Content = $"编号为{equipmentRepairModel.Code}的仪器报修单据需要审批处理。",
                    Url = "/equipment/equipmentRepair/handle",
                    Permission = "equipmentRepair:handle"
                };
                await _sysMessageService.AddSysMessage(message);
            }

            await equipmentRepairModel.UpdateAsync();
        }

        /// <summary>
        /// 删除单据
        /// </summary>
        [HttpPost("equipmentRepair/delete")]
        public async Task Delete(long id)
        {
            EquipmentRepair equipmentRepair = await _equipmentRepairRep.FirstOrDefaultAsync(u => u.Id == id);
            if (equipmentRepair == null)
                throw Oops.Oh("不存在此数据");

            await equipmentRepair.DeleteAsync();
        }

        /// <summary>
        /// 单据打印
        /// </summary>
        [HttpPost("equipmentRepair/print")]
        public async Task<string> Print(long id)
        {
            EquipmentRepair equipmentRepair = await _equipmentRepairRep.Include(s => s.Equipment)
                .ThenInclude(s => s.ExperimentStation)
                .FirstOrDefaultAsync(u => u.Id == id);
            if (equipmentRepair == null)
                throw Oops.Oh("不存在此数据");

            //获取模板路径
            var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath + "/template/EquipmentRepair.docx");
            //生成模板路径
            var reportUrl = $"/report/{equipmentRepair.Equipment.Name}-{equipmentRepair.Code}.docx";
            var reportPath = Path.Combine(App.WebHostEnvironment.WebRootPath + reportUrl);

            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == equipmentRepair.CreatedUserId, false);

            var userPhone = "";

            if (user != null)
            {
                userPhone = string.IsNullOrEmpty(user.Phone) ? user.Tel : user.Phone;
            }
            var value = new Dictionary<string, object>()
            {
                ["syzmc"] = equipmentRepair.Equipment.ExperimentStation.Name,
                ["djcode"] = equipmentRepair.Code,
                ["name"] = equipmentRepair.Equipment.Name,
                ["Specification"] = equipmentRepair.Equipment.Specification,
                ["yqcode"] = equipmentRepair.Equipment.Code,//仪器编号
                ["Username"] = equipmentRepair.CreatedUserName,
                ["createDate"] = equipmentRepair.CreatedTime,
                ["remark"] = equipmentRepair.FaultDescription,//故障描述
                ["phone"] = userPhone//联系方式
            };

            MiniWord.SaveAsByTemplate(reportPath, templatePath, value);

            equipmentRepair.ReportUrl = reportUrl;

            await _equipmentRepairRep.UpdateIncludeAsync(equipmentRepair, new[] { nameof(EquipmentRepair.ReportUrl) });

            return reportUrl;

        }

        /// <summary>
        /// 获取详细
        /// </summary>
        [HttpGet("equipmentRepair/detail")]
        public async Task<EquipmentRepairDetail> Detail(long id)
        {
            var equipmentRepair = await _equipmentRepairRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == id);
            if (equipmentRepair == null)
                throw Oops.Oh("不存在此数据");

            EquipmentRepairDetail detail = equipmentRepair.Adapt<EquipmentRepairDetail>();

            EquipmentInfo equipment = await _equipmentInfoRep.DetachedEntities
                                             .Include(x => x.EquipmentCategory)
                                             .Include(x => x.EquipmentFactory)
                                             .Include(x => x.ExperimentStation)
                                             .FirstOrDefaultAsync(u => u.Id == equipmentRepair.EquipmentId);
            if (equipment != null)
            {
                EquipmentInfoOutput info = new EquipmentInfoOutput()
                {
                    Id = equipment.Id,
                    Code = equipment.Code,
                    Name = equipment.Name,
                    EquipmentCategoryId = equipment.EquipmentCategoryId,
                    EquipmentCategoryName = equipment.EquipmentCategory.Name,
                    Specification = equipment.Specification,
                    Degree = equipment.Degree,
                    EquipmentImage = equipment.EquipmentImage,
                    ProduceTime = equipment.ProduceTime,
                    BuyTime = equipment.BuyTime,
                    EquipmentFactoryId = equipment.EquipmentFactoryId,
                    EquipmentFactoryName = equipment.EquipmentFactory.Name,
                    ExperimentStationId = equipment.ExperimentStationId,
                    ExperimentStationName = equipment.ExperimentStation.Name,
                    Remark = equipment.Remark,

                    EquipmentStatus = equipment.EquipmentStatus,
                    ValidStatus = equipment.ValidStatus,
                    Sort = equipment.Sort,
                };
                detail.EquipmentInfoOutput = info;
            }
            return detail;
        }

        /// <summary>
        /// 设备报修审核
        /// </summary>
        [HttpPost("equipmentRepair/handle")]
        [UnitOfWork]
        public async Task Handle(HandleEquipmentRepairInput input)
        {
            var equipmentRepair = await _equipmentRepairRep.DetachedEntities.Include(s => s.Equipment).FirstOrDefaultAsync(u => u.Id == input.Id);
            if (equipmentRepair == null)
                throw Oops.Oh("不存在此数据！");

            var isExist = await _equipmentRepairRep.DetachedEntities.AnyAsync(u => u.EquipmentId == input.EquipmentId && u.Status > DealStatus.ToBeAccept && u.Id == input.Id);
            if (isExist)
                throw Oops.Oh("此报修工单已被审核！");

            equipmentRepair.DealOpinon = input.DealOpinon;
            equipmentRepair.DealDescription = input.DealDescription;
            equipmentRepair.DealTime = DateTime.Now;
            equipmentRepair.DealUser = App.User?.FindFirst(ClaimConst.CLAINM_NAME)?.Value;

            // 更新设备状态、工单状态
            switch (input.DealOpinon)
            {
                case DealOpinon.DepotRepair:
                    // 返厂维修
                    equipmentRepair.Equipment.EquipmentStatus = EquipmentStatus.Repairing;
                    equipmentRepair.Status = DealStatus.ToBeAccept;
                    break;
                case DealOpinon.Repair:
                    // 内部维修
                    equipmentRepair.Equipment.EquipmentStatus = EquipmentStatus.Repairing;
                    equipmentRepair.Status = DealStatus.ToBeAccept;
                    break;
                case DealOpinon.Reject:
                    // 驳回时，恢复原设备的状态
                    equipmentRepair.Equipment.EquipmentStatus = equipmentRepair.EquipmentStatusBackup;
                    equipmentRepair.Status = DealStatus.Rejected;
                    break;
                case DealOpinon.Scrap:
                    // 直接报废
                    equipmentRepair.Equipment.EquipmentStatus = EquipmentStatus.Useless;
                    equipmentRepair.Status = DealStatus.Accepted;
                    break;
                default:
                    break;
            }
            await _equipmentRepairRep.UpdateNowAsync(equipmentRepair);

            await _equipmentInfoRep.UpdateIncludeAsync(equipmentRepair.Equipment, new[] { nameof(EquipmentInfo.EquipmentStatus) });

            //发送站内信-审核
            AddSysMessageInput message = new AddSysMessageInput
            {
                Title = $"验收编号为{equipmentRepair.Code}仪器报修单据",
                ParamId = equipmentRepair.Id,
                Tag = "仪器报修",
                Content = $"编号为{equipmentRepair.Code}的仪器报修单据需要验收处理。",
                Url = "/equipment/equipmentRepair/accept",
                Permission = "equipmentRepair:accept"
            };
            await _sysMessageService.AddSysMessage(message);
        }

        /// <summary>
        /// 设备报修验收
        /// </summary>
        [HttpPost("equipmentRepair/accept")]
        [UnitOfWork]
        public async Task Accept(HandleEquipmentRepairInput input)
        {
            var equipmentRepair = await _equipmentRepairRep.DetachedEntities.Include(s => s.Equipment).FirstOrDefaultAsync(u => u.Id == input.Id);
            if (equipmentRepair == null)
                throw Oops.Oh("不存在此数据！");

            var isExist = await _equipmentRepairRep.DetachedEntities.AnyAsync(u => u.EquipmentId == input.EquipmentId && (u.Status == DealStatus.Accepted || u.Status == DealStatus.Rejected) && u.Id == input.Id);
            if (isExist)
                throw Oops.Oh("此报修工单已被验收！");

            equipmentRepair.IsRepaired = input.IsRepaired;
            equipmentRepair.AcceptDescription = input.AcceptDescription;
            equipmentRepair.AcceptImage = input.AcceptImage;
            equipmentRepair.AcceptTime = DateTime.Now;
            equipmentRepair.AcceptUser = App.User?.FindFirst(ClaimConst.CLAINM_NAME)?.Value;
            equipmentRepair.Status = DealStatus.Accepted;
            await _equipmentRepairRep.UpdateNowAsync(equipmentRepair);

            // 更新设备状态
            equipmentRepair.Equipment.EquipmentStatus = input.EquipmentStatus;

            await _equipmentInfoRep.UpdateIncludeAsync(equipmentRepair.Equipment, new[] { nameof(EquipmentInfo.EquipmentStatus) });
        }

        /// <summary>
        /// 分页数据
        /// </summary>
        [HttpGet("equipmentRepair/page")]
        public async Task<PageResult<EquipmentRepairOutput>> QueryPage([FromQuery] EquipmentRepairPageInput input)
        {
            var code = !string.IsNullOrEmpty(input.Code?.Trim());
            var SearchValue = !string.IsNullOrEmpty(input.SearchValue?.Trim());

            var items = await _equipmentRepairRep.DetachedEntities.Include(s => s.Equipment)
                                         .Where((code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")))
                                         .Where((SearchValue, u => EF.Functions.Like(u.Equipment.Code, $"%{input.SearchValue.Trim()}%")
                                                                || EF.Functions.Like(u.Equipment.Name, $"%{input.SearchValue.Trim()}%")))
                                         .Where(input.Status.HasValue, u => u.Status == input.Status)
                                         .Where(input.CreatedUserId.HasValue, u => u.CreatedUserId == input.CreatedUserId)
                                         .Where(input.EquipmentId.HasValue, u => u.EquipmentId == input.EquipmentId)
                                         .Where(input.CreatedTimeStart.HasValue, u => u.CreatedTime >= input.CreatedTimeStart.Value && u.CreatedTime <= input.CreatedTimeEnd.Value)
                                         .OrderByDescending(u => u.CreatedTime)
                                         .Select(u => new EquipmentRepairOutput
                                         {
                                             Id = u.Id,
                                             Code = u.Code,
                                             EquipmentId = u.EquipmentId,
                                             EquipmentCode = u.Equipment.Code,
                                             EquipmentName = u.Equipment.Name,
                                             EquipmentStatus = u.Equipment.EquipmentStatus,

                                             FaultDescription = u.FaultDescription,
                                             FaultImage = u.FaultImage,
                                             FaultVideo = u.FaultVideo,
                                             CreatedTime = u.CreatedTime.Value,
                                             CreatedUserName = u.CreatedUserName,

                                             DealOpinon = u.DealOpinon,
                                             DealDescription = u.DealDescription,
                                             DealTime = u.DealTime.HasValue ? u.DealTime.Value : null,
                                             DealUser = u.DealUser,

                                             IsRepaired = u.IsRepaired,
                                             AcceptDescription = u.AcceptDescription,
                                             AcceptImage = u.AcceptImage,
                                             AcceptTime = u.AcceptTime,
                                             AcceptUser = u.AcceptUser,
                                             ReportUrl = u.ReportUrl,
                                             Status = u.Status,
                                         }).ToADPagedListAsync(input.PageNo, input.PageSize);

            return items;
        }
    }
}
